/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 d3leaf@126.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.mapperdb.builder;

import org.apache.ibatis.annotations.SelectKey;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.session.Configuration;

import com.mapperdb.builder.annotation.ProviderSqlSourceSupper;
import com.mapperdb.db.ResultEntity;
import com.mapperdb.mapping.EmptySqlSource;
import com.mapperdb.util.MapperUtils;
import com.mapperdb.util.StrKit;

public class StatementBuilder extends BasicBuilder {
	protected String mappedStatementId;
	protected MappedStatement mappedStatement;

	public StatementBuilder(Configuration configuration, Class<?> type) {
		super(configuration, type);
	}

	public StatementBuilder(Configuration configuration, Class<?> type, String mappedStatementId) {
		super(configuration, type);
		this.mappedStatementId = mappedStatementId;
	}

	public void parseStatement() {
		Class<?> parameterTypeClass = getParameterType(parameterTypes);

		StatementType statementType = StatementType.PREPARED;
		ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
		boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
		boolean flushCache = !isSelect;
		boolean useCache = isSelect;

		KeyGenerator keyGenerator;
		String keyProperty = "id";
		String keyColumn = null;
		if (SqlCommandType.INSERT.equals(sqlCommandType)) {
			// first check for SelectKey annotation - that overrides everything else
			SelectKey selectKey = resultEntity.selectKey();
			if (selectKey != null) {
				keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, parameterTypeClass, languageDriver);
				keyProperty = selectKey.keyProperty();
			} else {
				keyGenerator = configuration.isUseGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
			}
		} else {
			keyGenerator = new NoKeyGenerator();
		}

		String resultMapId = resultEntity.resultMapId();

		if (isSelect) {
			if (StrKit.isBlank(resultMapId)) resultMapId = parseResultMap();
		}

		mappedStatement = assistant.addMappedStatement(mappedStatementId, sqlSource, statementType, sqlCommandType, null, null,
				null, // ParameterMapID
				parameterTypeClass, resultMapId, // ResultMapID
				returnType, resultSetType, flushCache, useCache, false, // TODO issue #577
				keyGenerator, keyProperty, keyColumn, null, languageDriver, null);
	}

	public void buildSqlSource(ResultEntity resultEntity, Class<?> providerType, String providerMethodName) {
		MappedStatement ms = this.getMappedStatement();
		if (ms.getSqlSource() instanceof EmptySqlSource) {
			SqlSource sqlSource = new ProviderSqlSourceSupper(ms, resultEntity, providerType, providerMethodName);
			if (sqlSource != null) MapperUtils.setSqlSource(ms, sqlSource);
		}
	}

	// -------------------------------------------------------
	// attr
	// -------------------------------------------------------

	public MappedStatement getMappedStatement() {
		if (mappedStatement == null) throw new BuilderException("MappedStatement not parse .");
		return mappedStatement;
	}

	public void setMappedStatementId(String mappedStatementId) {
		this.mappedStatementId = mappedStatementId;
	}
}
